import hashlib
from stat import *
import os
import os.path
import filetype

from s2c.rules.conf import FIELD_DELIMITER,SYS_CURRENT


# FileInfo 文件的详细信息
# dict_type: current | base， current表示用户扫描当前系统，base 基础指纹库
class FileInfo:
    def __init__(self, filepath, dict_type=SYS_CURRENT):
        self.filepath = filepath
        self.dict_type = dict_type
        self.link = ''
        self.md5 = ''
        self.lmode = None
        self.mode = ''
        self.desc = ''

    def calc(self):
        self.calc_stat_mode()
        self.calc_md5()
        self.calc_filetype()

    def json(self):
        return {
            'path': self.filepath,
            'md5': self.md5,
            'mode': self.mode,
            'dict_type': self.dict_type,
            'link': self.link,
            'desc': self.desc
        }

    def fields(self):
        return FIELD_DELIMITER.join(
            [self.filepath, self.md5, str(self.mode), str(self.dict_type), self.link, self.desc])

    # 文件模式
    def calc_stat_mode(self):
        filepath = self.filepath
        try:
            lmode = os.lstat(filepath)[ST_MODE]
        except:
            lmode = None
        mode = 'UNKNOWN'  # 未知设备
        if lmode is None:
            mode = 'NONE'
        elif S_ISREG(lmode):
            mode = 'REG'  # 常规文件
        elif S_ISDIR(lmode):
            mode = 'DIR'  # 目录
        elif S_ISLNK(lmode):
            mode = 'LNK'  # 软连接
            try:
                self.link = os.readlink(filepath)
            except:
                self.link = ''
        elif S_ISCHR(lmode):
            mode = 'CHR'  # 字符设备
        elif S_ISBLK(lmode):
            mode = 'BLK'  # 块设备
        elif S_ISFIFO(lmode):
            mode = 'FIFO'  # 管道设备
        elif S_ISSOCK(lmode):
            mode = 'SOCK'  # 套接字
        else:
            mode = 'UNKNOWN'  # 未知设备
        self.lmode = lmode
        self.mode = mode

    # 计算 md5
    def calc_md5(self):
        hash_factory = hashlib.md5
        self.md5 = ''
        filename = ''
        try:
            if self.lmode is None:
                return ''
            if S_ISLNK(self.lmode):
                filename = self.link

            if S_ISREG(self.lmode):
                filename = self.filepath

            if filename == '':
                return ''
            fsize = os.path.getsize(filename)
            h = hash_factory()
            with open(filename, 'rb') as f:
                for chunk in iter(lambda: f.read(8192), b''):
                    h.update(chunk)
            self.md5 = h.hexdigest()
        except IOError:
            self.md5 = ''
            return '<unable to read file>'

    # 计算 filetype
    def calc_filetype(self):
        self.desc = ''
        try:
            kind = filetype.guess(self.filepath)

            if kind is not None:
                self.desc = kind.mime
        except:
            self.desc = ''

    def __str__(self):
        return str(self.json())

    def dump(self):
        print(str(self))


# end class

def field_names():
    return FIELD_DELIMITER.join(['path', 'md5', 'mode', 'dict_type', 'link', 'desc'])
